package com.leyou.item.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.conditions.query.QueryChainWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.core.type.TypeReference;
import com.leyou.common.dto.PageDTO;
import com.leyou.common.exception.LyException;
import com.leyou.common.utils.JsonUtils;
import com.leyou.item.dto.SkuDTO;
import com.leyou.item.dto.SpecParamDTO;
import com.leyou.item.dto.SpuDTO;
import com.leyou.item.dto.SpuDetailDTO;
import com.leyou.item.entity.Category;
import com.leyou.item.entity.Sku;
import com.leyou.item.entity.Spu;
import com.leyou.item.entity.SpuDetail;
import com.leyou.item.mapper.SpuMapper;
import com.leyou.item.service.*;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

@Service
public class SpuServiceImpl extends ServiceImpl<SpuMapper, Spu> implements SpuService {

    @Autowired
    private CategoryService categoryService;

    @Autowired
    private BrandService brandService;

    @Autowired
    private SpuDetailService spuDetailService;

    @Autowired
    private SkuService skuService;

    @Autowired
    private SpecParamService paramService;


    @Override
    public PageDTO<SpuDTO> pageQuery(Integer page, Integer rows, Long cId, Long bid, Boolean saleable, Long id) {
        // 1.健壮性
        int current = Math.max(page, 1);
        int size = Math.max(rows, 5);

        //链式查询，一次性封装6个查询属性到查询条件中，动态sql，有值，根据其查询否则动态sql不会生效
        Page<Spu> spuPage = query()
                .eq(cId != null, "cid3", cId)
                .eq(bid != null, "brand_id", bid)
                .eq(saleable != null, "saleable", saleable)
                .eq(id != null, "id", id)
                .page(new Page(current,size));

        long total = spuPage.getTotal();
        long pages = spuPage.getPages();

        List<SpuDTO> spuDTOS = SpuDTO.convertEntityList(spuPage.getRecords());

        spuDTOS.forEach(spuDTO -> {

            //TODO 如果分类及品牌有重复使用的可能，不要每次都查询数据库
            handlerName(spuDTO);

        });


        return new PageDTO<>(total, pages, spuDTOS);
    }

    private void handlerName(SpuDTO spuDTO) {
        //根据分类的id集合查询分类集合，从集合中取出分类的名称，并把多个分类名称拼接为字符串，以/分隔
        String names = this.categoryService.listByIds(spuDTO.getCategoryIds())
                .stream()
                .map(Category::getName)
                .collect(Collectors.joining("/"));
        spuDTO.setCategoryName(names);

        //根据品牌id获取到对应的品牌对象，并获取到名称
        spuDTO.setBrandName(this.brandService.getById(spuDTO.getBrandId()).getName());
    }


    @Autowired
    private AmqpTemplate amqpTemplate;

    //新增要发消息，告诉，搜索服务，新来了一个商品（也可以不发，默认不上架，新增完成后必然要做上架）
    @Transactional
    @Override
    public void addGoods(SpuDTO spuDTO) {

        //dto===>entity

        Spu spu = spuDTO.toEntity(Spu.class);

        //保存spu并主键回显
        boolean result = save(spu);

        if (!result) {
            throw new LyException(500, "商品spu保存失败");
        }

        //TODO 保存spuDetail sku
        //从spu中获取到spuDetail，转换为spuDetailEntity
        SpuDetail spuDetail = spuDTO.getSpuDetail().toEntity(SpuDetail.class);
        spuDetail.setSpuId(spu.getId());

        result = this.spuDetailService.save(spuDetail);

        if (!result) {
            throw new LyException(500, "商品spuDetail保存失败");
        }

        //TODO spuDTO===>List<SkuDTO>====>List<Sku>==>sku.setSpuId(spu.getId())

        //从spuDTO中获取到skuDTO，转为sku同时赋值spuId
        List<Sku> skus = spuDTO.getSkus().stream().map(skuDTO -> {
            skuDTO.setSpuId(spu.getId());
            skuDTO.setSaleable(true); //设置上架默认为true
            return skuDTO.toEntity(Sku.class);
        }).collect(Collectors.toList());

        this.skuService.saveBatch(skus);


        //向mq发送消息
        amqpTemplate.convertAndSend("ly-item","goods.add",spu.getId());

    }

    @Override
    public void modifySaleable(Long id, Boolean saleable) {
        //TODO 1,指定spu，及sku，修改其属性，saleable 的值为传入的值，true||false

        Spu spu = new Spu();
        spu.setSaleable(saleable);


        //update tb_spu set saleable = false where id = 10086
        boolean result = update(spu, new QueryWrapper<Spu>().eq("id", id));

        if (!result) {
            throw new LyException(500, "商品spu上下架状态修改失败");
        }

        //修改sku
        Sku sku = new Sku();
        sku.setSaleable(saleable);
        //update tb_sku set saleable = false where spu_id = 10086
        result = this.skuService.update(sku, new QueryWrapper<Sku>().eq("spu_id", id));

        if (!result) {
            throw new LyException(500, "商品spu上下架状态修改失败");
        }

        String key = saleable ? "goods.add" : "goods.remove";


        //向mq发送消息
        amqpTemplate.convertAndSend("ly-item",key,id);

    }

    @Override
    public SpuDTO querySpuById(Long spuId) {

        //根据spuId查询对应的spuEntity，然后把其转换为spuDTO
        SpuDTO spuDTO = new SpuDTO(getById(spuId));

        //复用分类名称及品牌名称的业务方法
        //handlerName(spuDTO);

        //根据spuId查询对应的spuDetail，并转为dto
        spuDTO.setSpuDetail(new SpuDetailDTO(this.spuDetailService.getById(spuId)));

        //根据spuId查询对应的所有的sku集合，并转为DTO，
        spuDTO.setSkus(SkuDTO.convertEntityList(this.skuService.query().eq("spu_id", spuId).list()));

        return spuDTO;
    }

    @Override
    public void updateGoods(SpuDTO spuDTO) {
        //spuDTO==》获取id，如果有id，说明spu要被修改，只提交了要修改的值，所以spuDTO转为spuEntity后，只有要修改的属性有值（id除外）

        boolean result;
        if (null != spuDTO.getId()) {
            result = updateById(spuDTO.toEntity(Spu.class));

            if (!result) {
                throw new LyException(500, "商品修改SPU信息失败");
            }
        }

        //如果spuDTO中包含了属性，spuDetail，则表示要修改spuDetail
        SpuDetailDTO spuDetailDTO = spuDTO.getSpuDetail();

        if (null != spuDetailDTO) {
            result = this.spuDetailService.updateById(spuDetailDTO.toEntity(SpuDetail.class));

            if (!result) {
                throw new LyException(500, "商品修改SPUDetail信息失败");
            }
        }


        //判断sku是否需要更改，数组长度为0表示不要更新
        List<SkuDTO> skuDTOS = spuDTO.getSkus();

        //sku实际处理时，有三种可能性，1，有id修改updateById（）（saleable为null）或者删除removeById（）（saleable为false），2没有id，新增，save

        //TODO sku修改时候，有个总的result，如果为false，抛异常，sku修改失败
        if (0 != skuDTOS.size()) {
            //更新有两种可能性，①：修改，②：新增

            for (SkuDTO skuDTO : skuDTOS) {

                Sku sku = skuDTO.toEntity(Sku.class);
                //有id，则修改
                if (null != skuDTO.getId()) {

                    if (false == skuDTO.getSaleable()) {
                        this.skuService.removeById(sku.getId());
                    }
                    this.skuService.updateById(sku);
                } else {
                    sku.setSaleable(true);
                    this.skuService.save(sku);
                }
            }

        }


    }

    @Override
    public List<SkuDTO> querySkuByIds(List<Long> ids) {

        List<Sku> skus = this.skuService.listByIds(ids);

        if (CollectionUtils.isEmpty(skus)) {
            throw new LyException(204, "对应的sku没有查到");
        }

        return SkuDTO.convertEntityList(skus);
    }

    @Override
    public List<SkuDTO> querySkuBySpuId(Long spuId) {

        //select * from tb_sku where spu_id = #{spuId}
        List<Sku> skus = this.skuService.query().eq("spu_id", spuId).list();

        if (CollectionUtils.isEmpty(skus)) {
            throw new LyException(204, "对应的sku没有查到");
        }
        return SkuDTO.convertEntityList(skus);
    }

    @Override
    public SpuDetailDTO querySpuDetailById(Long spuId) {

        SpuDetail spuDetail = this.spuDetailService.getById(spuId);
        if (null == spuDetail) {
            throw new LyException(204, "对应的spuDetail没有查到");
        }

        return new SpuDetailDTO(spuDetail);
    }


    /**
     * 根据查询条件，去给规格参数的属性value赋值
     *
     * @param id
     * @param searching
     * @return
     */
    @Override
    public List<SpecParamDTO> querySpecValues(Long id, Boolean searching) {

        // 1.准备规格参数value
        // 1.1.根据spuId查询spuDetail，
        SpuDetail detail = this.spuDetailService.getById(id);
        // 1.2.获取其中的规格参数键值对，转为一个map ,json字符串，key类型，第三个value类型

        //getSpecification
        /**
         * specPramId1, 华为
         * specPramId2, Mate30
         * specPramId3, 5.5
         * specPramId4, 128
         * specPramId5, 塑料
         * specPramId6, 智能
         *
         */
        Map<Long, Object> specValues = JsonUtils.toMap(detail.getSpecification(), Long.class, Object.class);


        // 2.准备规格参数对象
        // 2.1.根据id查询spu，获取商品分类信息
        Spu spu = getById(id);
        // 2.2.根据分类id查询规格参数集合，如果searching不为空，还要加上searching条件
        List<SpecParamDTO> params = paramService.queryParams(spu.getCid3(), null, searching);

        for (SpecParamDTO param : params) {

            //根据规格参数的id从规格参数表中获取到对应的规格参数的值，并赋值给对应的规格参数对象
            param.setValue(specValues.get(param.getId()));
        }


        return params;
    }

}
